﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace VentAnalyServer
{
    public class DwgService
    {
        public static string APP_PATH = Path.GetDirectoryName(AppDomain.CurrentDomain.SetupInformation.ApplicationBase);
        public static string DWG_2_JSON_EXE = Path.Combine(APP_PATH, "DwgTool\\Dwg2Json.exe");
        public static string JSON_2_DWG_EXE = Path.Combine(APP_PATH, "DwgTool\\Json2Dwg.exe");

        public static string DWG_2_JSON_ERROR_FILE = Path.Combine(APP_PATH, "DwgTool\\Dwg2Json.err");
        public static string JSON_2_DWG_ERROR_FILE = Path.Combine(APP_PATH, "DwgTool\\Json2Dwg.err");

        // 预先定义的块文件
        public static string PREDEFINED_BLOCK_DWG_FILE = Path.Combine(APP_PATH, "resources\\dwg\\blocks.dwg");
        // dwg文件缓存: test.dwg -> test.bak
        public static string DWG_FILE_CACHE_PATH = Path.Combine(APP_PATH, "resources\\cache");

        public static void UpdatePredefinedDwgBlocks(string dwgFile)
        {
            UpdateDwgBlocks(dwgFile, PREDEFINED_BLOCK_DWG_FILE);
        }

        // 读取blockDwgFile文件, 更新dwgFile文件内的块定义
        // 注: 这2个文件扩展名均为*.dwg
        public static void UpdateDwgBlocks(string dwgFile, string blockDwgFile)
        {
            if (!File.Exists(DWG_2_JSON_EXE))
            {
                throw new Exception(string.Format("Dwg2Json.exe路径不存在:{0}", DWG_2_JSON_EXE));
            }
            if (!File.Exists(JSON_2_DWG_EXE))
            {
                throw new Exception(string.Format("Json2Dwg.exe路径不存在:{0}", JSON_2_DWG_EXE));
            }
            if (!File.Exists(dwgFile))
            {
                throw new Exception(string.Format("Dwg文件不存在:{0}", dwgFile));
            }
            if (!File.Exists(blockDwgFile))
            {
                throw new Exception(string.Format("块定义文件不存在:{0}", blockDwgFile));
            }

            // 构造命令行参数选项
            List<string> args = new List<string>();

            // 和块定义dwg文件在同一路径下的json文件
            string jsonFile = FileUtil.BuildFileNameWithNewExtension(blockDwgFile, ".json");                       
            if (!File.Exists(jsonFile))
            {
                // 步骤1:块定义DWG --> JSON
                args.Add("--dwg");
                args.Add(blockDwgFile);
                args.Add("--json");
                args.Add(jsonFile);
                // 不解析database、词典、内置图元、自定义图元
                args.Add("--without-database");
                args.Add("--without-dict");
                args.Add("--without-builtin-entity");
                args.Add("--without-custom-entity");

                // 启动进程, 并且同步等待
                ProcUtil.LaunchExe(DWG_2_JSON_EXE, args.ToArray(), false);

                if (File.Exists(DWG_2_JSON_ERROR_FILE))
                {
                    throw new Exception(string.Format("Dwg2Json运行错误, 错误信息:{0}", File.ReadAllText(DWG_2_JSON_ERROR_FILE)));
                }
            }
            
            // 步骤2: JSON --> 要更新的DWG
            args.Clear();
            args.Add("--dwg");
            args.Add(dwgFile);
            args.Add("--json");
            args.Add(jsonFile);
            // 不解析database、词典、内置图元、自定义图元
            args.Add("--without-database");
            args.Add("--without-dict");
            args.Add("--without-builtin-entity");
            args.Add("--without-custom-entity");

            // 启动进程, 并且同步等待
            // JSON --> DWG(主要是覆盖块定义)
            ProcUtil.LaunchExe(JSON_2_DWG_EXE, args.ToArray(), false);

            if (File.Exists(JSON_2_DWG_ERROR_FILE))
            {
                throw new Exception(string.Format("Json2Dwg运行错误, 错误信息:{0}", File.ReadAllText(JSON_2_DWG_ERROR_FILE)));
            }
        }

        // enableGzipCompression -- 是否压缩生成的json数据
        public static string ParseDwgFile(string dwgFile, string jsonFile, int chunkSize = 10000, bool enableGzipCompression = false)
        {
            if (!System.IO.Directory.Exists(DWG_FILE_CACHE_PATH))//如果不存在就创建file文件夹
            {
                System.IO.Directory.CreateDirectory(DWG_FILE_CACHE_PATH);
            }
            if (!File.Exists(DWG_2_JSON_EXE))
            {
                throw new Exception(string.Format("Dwg2Json.exe路径不存在:{0}", DWG_2_JSON_EXE));
            }
            if (!File.Exists(dwgFile))
            {
                throw new Exception(string.Format("Dwg文件不存在:{0}", dwgFile));
            }

            Console.WriteLine("dwg文件:{0}", dwgFile);
            Console.WriteLine("json文件:{0}", jsonFile);
            Console.WriteLine("exe文件:{0}", DWG_2_JSON_EXE);

            // 复制dwg文件到缓存路径下做备份
            // 文件名格式: test.dwg --> test_20210918212550.bak
            string bakFileName = $"{Path.GetFileNameWithoutExtension(dwgFile)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.bak";
            System.IO.File.Copy(dwgFile, Path.Combine(DWG_FILE_CACHE_PATH, bakFileName));

            // 构造命令行参数选项
            List<string> args = new List<string>();
            args.Add("--dwg");
            args.Add(dwgFile);
            args.Add("--json");
            args.Add(jsonFile);
            args.Add("--chunk");
            args.Add(chunkSize.ToString());
            if (enableGzipCompression)
            {
                args.Add("--zip");
            }

            // 启动进程, 并且同步等待
            ProcUtil.LaunchExe(DWG_2_JSON_EXE, args.ToArray(), false);

            if (File.Exists(DWG_2_JSON_ERROR_FILE))
            {
                throw new Exception(string.Format("Dwg2Json运行错误, 错误信息:{0}", File.ReadAllText(DWG_2_JSON_ERROR_FILE)));
            }

            return File.ReadAllText(jsonFile);
        }

        public static void SaveDwgData(IHttpClientFactory httpClientFactory, string url, string token, string key, JObject data)
        {
            // 构造headers
            Dictionary<string, string> headers = new Dictionary<string, string>();
            headers["Accept"] = "application/json";
            if (token.Length > 0)
            {
                headers["Authorization"] = token;
            }

            JObject obj1 = new JObject()
            {
                new JProperty("key", key),
                new JProperty("isFromScratch", true),
                new JProperty("database", data["database"]),
                new JProperty("layers", data["layers"]),
                new JProperty("lineTypes", data["lineTypes"]),
                new JProperty("textStyles", data["textStyles"]),
                new JProperty("dimStyles", data["dimStyles"]),
                new JProperty("dicts", data["dicts"]),
            };
            // 第一次请求(同步)
            // 发送数据库、图层、线型、标注样式、文字样式、自定义词典
            string res = HttpUtil.HttpPost(httpClientFactory.CreateClient(), url, JsonConvert.SerializeObject(obj1), headers: headers);

            List<Task<string>> tasks = new List<Task<string>>();

            // 其它请求(异步)

            // 发送块定义
            JObject obj2 = new JObject()
            {
                new JProperty("key", key),
                new JProperty("isFromScratch", false),
                new JProperty("blocks", data["blocks"])
            };
            tasks.Add(HttpUtil.HttpPostAsync(httpClientFactory.CreateClient(), url, JsonConvert.SerializeObject(obj2), headers: headers));

            // 分批次发送内置图元
            // 注: 内置图元个数太多, 传输数据量过大, 可能会被服务器拒绝, 因此分块分批次
            foreach (var item in data["builtinEntities"])
            {
                JArray entities = (JArray)item;
                JObject obj3 = new JObject()
            {
                new JProperty("key", key),
                new JProperty("isFromScratch", false),
                new JProperty("builtinEntities", entities),
            };
                tasks.Add(HttpUtil.HttpPostAsync(httpClientFactory.CreateClient(), url, JsonConvert.SerializeObject(obj3), headers: headers));
            }

            // 分批次发送自定义图元
            foreach (var item in data["customEntities"])
            {
                JArray entities = (JArray)item;
                JObject obj4 = new JObject()
            {
                new JProperty("key", key),
                new JProperty("isFromScratch", false),
                new JProperty("customEntities", entities),
            };
                tasks.Add(HttpUtil.HttpPostAsync(httpClientFactory.CreateClient(), url, JsonConvert.SerializeObject(obj4), headers: headers));
            }
            // 等待异步完成
            Task.WaitAll(tasks.ToArray());
        }

        public static string OpenDwgData(IHttpClientFactory httpClientFactory, string url, string token, string key)
        {
            // 构造headers
            Dictionary<string, string> headers = new Dictionary<string, string>();
            headers["Accept"] = "application/json";
            if (token.Length > 0)
            {
                headers["Authorization"] = token;
            }

            // 查询字符串参数
            Dictionary<string, string> qsParams = new Dictionary<string, string>()
            {
                {"key", key}
            };

            // 请求key对应的dwg数据
            return HttpUtil.HttpGet(httpClientFactory.CreateClient(), url, qsParams, headers: headers);
        }


        public static string MakeDwgFile(string dwgFile, string jsonFile, string outFile)
        {
            if (!File.Exists(JSON_2_DWG_EXE))
            {
                throw new Exception(string.Format("Json2Dwg.exe路径不存在:{0}", JSON_2_DWG_EXE));
            }
            if (!File.Exists(dwgFile))
            {
                throw new Exception(string.Format("Dwg文件不存在:{0}", dwgFile));
            }

            // 启动进程
            // DWG_2_JSON_ERROR_FILE和Dwg2Json.exe在同一个路径下!
            //string errFile = Path.Combine(Path.GetDirectoryName(exeFile), JSON_2_DWG_ERROR_FILE);

            Console.WriteLine("dwg文件:{0}", dwgFile);
            Console.WriteLine("json文件:{0}", jsonFile);
            Console.WriteLine("exe文件:{0}", JSON_2_DWG_EXE);

            // 构造命令行参数选项
            List<string> args = new List<string>();
            args.Add("--dwg");
            args.Add(dwgFile);
            args.Add("--json");
            args.Add(jsonFile);
            if (outFile != null)
            {
                args.Add("--out");
                args.Add(outFile);
            }

            // 启动进程, 并且同步等待
            ProcUtil.LaunchExe(JSON_2_DWG_EXE, args.ToArray(), false);

            if (File.Exists(JSON_2_DWG_ERROR_FILE))
            {
                throw new Exception(string.Format("Json2Dwg运行错误, 错误信息:{0}", File.ReadAllText(JSON_2_DWG_ERROR_FILE)));
            }

            string newDwgFile = null;
            if (outFile == null)
            {
                // 直接覆盖原始dwg文件
                newDwgFile = dwgFile;
            }
            else
            {
                // 返回新生成的dwg文件路径
                newDwgFile = outFile;
            }
            if (newDwgFile == null || !File.Exists(newDwgFile))
            {
                throw new Exception(string.Format("生成的dwg文件{0}不存在!", newDwgFile));
            }

            return newDwgFile;
        }
    }
}
